using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using SimpleJSON;
using UnityEngine;
using Gj.Network.IpRouting;

namespace Gj.DarkLoong
{
    public class Api
    {
        public enum Method
        {
            Get, 
            Post,
            Put,
            Delete,
        }
        
        private static HttpClientHandler handler;
        private static HttpClient client;
        private static HttpClient cookieClient;
        public static string API_DOMAIN = "game.ueffort.com";
        public static string API_BASE_URL = $"http://{API_DOMAIN}";
        public static Api Instance;
        public static List<string> cookies;

        // IP路由相关
        private static IpRouterManager _ipRouterManager;
        private static readonly char[] chars =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();

        public static string Generate(int length)
        {
            var result = new StringBuilder(length);
            using (var rng = RandomNumberGenerator.Create())
            {
                var uintBuffer = new byte[sizeof(uint)];
                while (result.Length < length)
                {
                    rng.GetBytes(uintBuffer);
                    uint num = BitConverter.ToUInt32(uintBuffer, 0);
                    result.Append(chars[num % chars.Length]);
                }
            }
            return result.ToString();
        }
        static Api()
        {
            Instance = new Api();
            _ipRouterManager = IpRouterManager.Default;

            // 初始化HttpClient
            InitializeHttpClient();
        }

        /// <summary>
        /// 初始化HttpClient，支持IP路由
        /// </summary>
        private static void InitializeHttpClient()
        {
            handler = new HttpClientHandler
            {
                UseCookies = true,
                CookieContainer = new CookieContainer(),
            };

            cookieClient = new HttpClient(handler);

            client = new HttpClient();

            // 设置默认超时
            client.Timeout = TimeSpan.FromSeconds(30);
        }

        /// <summary>
        /// 初始化默认IP列表
        /// </summary>
        private static void InitializeDefaultIps()
        {
            _ipRouterManager.InitializeDefaultIps();
        }

        public static void AddIps(string[] ips)
        {
            foreach (var ip in ips)
            {
                _ipRouterManager.AddIp(ip);
            }

            // 初始化默认IP列表
            InitializeDefaultIps();
        }

        /// <summary>
        /// 使用真正的IP路由客户端发送请求
        /// 完全不修改URL，通过Socket直接连接到指定IP
        /// </summary>
        private static async Task<string> SendWithIpRouting(
            string originalUrl,
            string targetIp,
            int targetPort,
            string method,
            string data = null,
            Dictionary<string, string> headers = null)
        {
            try
            {
                Debug.Log($"[Api] Sending request via TRUE IP routing: {targetIp}:{targetPort}");
                Debug.Log($"[Api] Original URL: {originalUrl}");
                Debug.Log($"[Api] URL is NOT modified - using Socket connection");

                return await TrueIpRouterClient.SendRequest(
                    originalUrl,
                    targetIp,
                    targetPort,
                    method,
                    data,
                    headers);
            }
            catch (Exception ex)
            {
                Debug.LogError($"[Api] TRUE IP routing request failed: {ex.Message}");
                throw;
            }
        }

        public static Dictionary<string, string> BaseHeader()
        {
            var header = new Dictionary<string, string>();
            var noise = Generate(32);
            header["app_key"] = DarkLoong.settings.AppKey;
            header["secret"] = DarkLoong.settings.AppSecret;
            header["noise"] = noise;
            header["sign"] = SignSha1(header);
            header.Remove("secret");
            header.Remove("app_key");
            
            return header;
        }

        public static Dictionary<string, string> CookieHeader()
        {
            var header = BaseHeader();
            if (cookies != null)
            {
                foreach (var cookie in cookies)
                {
                    var d = cookie.Split("=");
                    handler.CookieContainer.Add(new Uri(API_BASE_URL), new Cookie(d[0], d[1]));
                }
                header.Add("Cookie", string.Join("; ", cookies));
                // Debug.LogError($"cookie: {string.Join("; ", cookies)}");
            }
            
            return header;
        }
        public static string GetSignContent(Dictionary<string, string> data)
        {
            var keys = Enumerable.ToList(data
                    .Where(kv => kv.Value != null && kv.Key != "sign")
                    .Select(kv => kv.Key)
                    .OrderBy(k => k));

            var parts = new List<string>();
            foreach (var key in keys)
            {
                parts.Add($"{key}={data[key]}");
            }

            return string.Join("&", parts);
        }

        public static string SignSha1(Dictionary<string, string> data)
        {
            var content = GetSignContent(data);
            // Debug.LogError("sign:" + content);
            using (var sha1 = SHA1.Create())
            {
                var bytes = Encoding.UTF8.GetBytes(content);
                var hash = sha1.ComputeHash(bytes);
                return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
            }
        }

        public static string Md5(string input)
        {
            using (var md5 = MD5.Create())
            {
                var bytes = Encoding.UTF8.GetBytes(input);
                var hash = md5.ComputeHash(bytes);
                return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
            }
        }

        public static string GetError(JSONNode response)
        {
            return response["status"].AsInt != 200 ? response["message"].Value : "";
        }

        public static void AutoResult(JSONNode response, Action<JSONObject, string> callback)
        {
            var err = GetError(response);
            var item = err == "" ? response["result"].AsObject : new JSONObject();
            callback(item, err);
        }

        public static void AutoResult(JSONNode response, Action<JSONArray, string> callback)
        {
            var err = GetError(response);
            var item = err == "" ? response["result"].AsArray : new JSONArray();
            callback(item, err);
        }

        public static void AutoResult(JSONNode response, Action<bool, string> callback)
        {
            var err = GetError(response);
            var item = err == "" ? response["result"].AsBool : false;
            callback(item, err);
        }

        public static async Task<JSONNode> Get(string url, JSONObject data, Dictionary<string, string> header = null)
        {
            return await Request(Method.Get, url, data, header);
        }

        public static async Task<JSONNode> Post(string url, JSONNode data, Dictionary<string, string> header = null)
        {
            return await Request(Method.Post, url, data, header);
        }

        public static async Task<JSONNode> Put(string url, JSONNode data, Dictionary<string, string> header = null)
        {
            return await Request(Method.Put, url, data, header);
        }

        public static async Task<JSONNode> Delete(string url, JSONNode data, Dictionary<string, string> header = null)
        {
            return await Request(Method.Delete, url, data, header);
        }

        public static async Task<JSONNode> Request(Method method, string url, JSONNode data, Dictionary<string, string> header = null)
        {
            Task<JSONNode> request = null;
            try
            {
                request = method switch
                {
                    Method.Get => SendWithRetry(HttpMethod.Get, url, data, header),
                    Method.Post => SendWithRetry(HttpMethod.Post, url, data, header),
                    Method.Put => SendWithRetry(HttpMethod.Put, url, data, header),
                    Method.Delete => SendWithRetry(HttpMethod.Delete, url, data, header),
                    _ => throw new Exception("method is empty"),
                };
                return await request;
            }
            catch (Exception e)
            {
                if (e.Message == "method is empty") return new JSONObject(){ { "status", 591 }, { "message", "格式错误" }, { "result", "" } };
                return new JSONObject(){ { "status", 592 }, { "message", "超时" }, { "result", "" } };
            }
        }

        /// <summary>
        /// 带重试机制的HTTP请求发送，全部失败，返回失败
        /// </summary>
        private static async Task<JSONNode> SendWithRetry(HttpMethod method, string url, JSONNode data, Dictionary<string, string> header = null)
        {
            Exception lastException = null;

            for (int attempt = 0; attempt < _ipRouterManager.GetMaxRetries(); attempt++)
            {
                try
                {
                    var originalUrl = API_BASE_URL + "/" + DarkLoong.settings.Name + url;
                    var requestIp = "";
                    var bestIp = _ipRouterManager.GetBestIp();
                    if (bestIp != null) requestIp = bestIp.GetRequestIp();

                    LogTools.Log($"Attempt {attempt + 1}/{_ipRouterManager.GetMaxRetries()} - Original URL: {originalUrl}");
                    LogTools.Log($"Attempt {attempt + 1}/{_ipRouterManager.GetMaxRetries()} - Request IP: {requestIp}, Host: {API_BASE_URL}");

                    // 使用IP路由发送请求
                    string response = null;
                    if (!string.IsNullOrEmpty(requestIp))
                    {
                        var ipParts = requestIp.Split(':');
                        if (ipParts.Length == 2 && int.TryParse(ipParts[1], out int port))
                        {
                            // 准备请求数据
                            string requestData = null;
                            if (data != null)
                            {
                                requestData = data.ToString();
                            }

                            // 准备请求头
                            var requestHeaders = new Dictionary<string, string>();
                            if (header != null)
                            {
                                foreach (var h in header)
                                {
                                    requestHeaders[h.Key] = h.Value;
                                }
                            }

                            try
                            {
                                // 使用IP路由发送请求
                                response = await SendWithIpRouting(
                                    originalUrl,
                                    ipParts[0],
                                    port,
                                    method.Method,
                                    requestData,
                                    requestHeaders);
                            }
                            catch (Exception ipRoutingEx)
                            {
                                LogTools.Error($"IP routing failed: {ipRoutingEx.Message}");
                                // IP路由失败，继续使用HttpClient作为后备方案
                                response = null;
                            }
                        }
                    }

                    // 如果没有IP路由或IP路由失败，使用原始HttpClient
                    if (string.IsNullOrEmpty(response))
                    {
                        try
                        {
                            JSONNode result = null;
                            switch (method.Method.ToUpper())
                            {
                                case "GET":
                                    result = await GetInternal(data as JSONObject, header, originalUrl);
                                    break;
                                case "POST":
                                    result = await PostInternal(data, header, originalUrl);
                                    break;
                                case "PUT":
                                    result = await PutInternal(data, header, originalUrl);
                                    break;
                                case "DELETE":
                                    result = await DeleteInternal(data, header, originalUrl);
                                    break;
                            }
                            response = result?.ToString();
                        }
                        catch (Exception httpClientEx)
                        {
                            LogTools.Error($"HttpClient fallback also failed: {httpClientEx.Message}");
                            throw; // 重新抛出异常，让重试机制处理
                        }
                    }

                    // 请求成功，重置当前IP的失败计数
                    var currentIp = _ipRouterManager.GetBestIp();
                    if (currentIp != null)
                    {
                        _ipRouterManager.ResetIpStatus(currentIp.ip, currentIp.port);
                    }

                    return JSON.Parse(response);
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    Debug.LogException(ex);
                    LogTools.Log($"Request attempt {attempt + 1} failed: {ex.Message}");

                    // 标记当前IP为失败
                    var currentIp = _ipRouterManager.GetBestIp();
                    if (currentIp != null)
                    {
                        _ipRouterManager.MarkIpFailed(currentIp.ip, currentIp.port);
                    }

                    // 如果不是最后一次尝试，等待后重试
                    if (attempt < _ipRouterManager.GetMaxRetries() - 1)
                    {
                        await Task.Delay(_ipRouterManager.GetRetryDelayMs() * (attempt + 1)); // 递增延迟

                        // 重新检查IP延迟，选择新的最佳IP
                        await _ipRouterManager.CheckAllLatencyAsync();
                    }
                }
            }

            // 所有重试都失败了
            LogTools.Error($"All {_ipRouterManager.GetMaxRetries()} attempts failed. Last error: {lastException?.Message}");
            throw lastException ?? new Exception("All retry attempts failed");
        }

        /// <summary>
        /// 内部GET方法，使用HttpClient直接连接到指定IP
        /// </summary>
        private static async Task<JSONNode> GetInternal(JSONObject data, Dictionary<string, string> header, string requestUrl)
        {
            LogTools.Log($"Get {requestUrl} {(data == null ? "empty" : data)}");
            var query = "";
            if (data != null && data.Count > 0)
            {
                var e = data.GetEnumerator();
                while (e.MoveNext())
                {
                    var current = (KeyValuePair<string, JSONNode>)e.Current;
                    if (current.Value.IsArray)
                    {
                        var a = current.Value.AsArray;
                        foreach (var v in a.Children)
                        {
                            query += $"{current.Key}={v.Value}&";
                        }
                    }
                    else
                    {
                        query += $"{current.Key}={current.Value.Value}&";
                    }
                }
                LogTools.Log($"Query {query}");
            }

            // 使用修改后的URL（可能包含IP地址）
            var requestUrlWithQuery = $"{requestUrl}?{query}";
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrlWithQuery);

            return await Send(requestMessage, header);
        }

        /// <summary>
        /// 内部POST方法，使用HttpClient直接连接到指定IP
        /// </summary>
        private static async Task<JSONNode> PostInternal(JSONNode data, Dictionary<string, string> header, string requestUrl)
        {
            LogTools.Log($"Post {requestUrl} {(data == null ? "empty" : data)}");
            var content = new StringContent((data == null ? "" : data.ToString()), Encoding.UTF8, "application/json");

            // 使用修改后的URL（可能包含IP地址）
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl)
            {
                Content = content
            };

            return await Send(requestMessage, header);
        }

        /// <summary>
        /// 内部PUT方法，使用HttpClient直接连接到指定IP
        /// </summary>
        private static async Task<JSONNode> PutInternal(JSONNode data, Dictionary<string, string> header, string requestUrl)
        {
            LogTools.Log($"Put {requestUrl} {(data == null ? "empty" : data.ToString())}");
            var content = new StringContent((data == null ? "" : data.ToString()), Encoding.UTF8, "application/json");

            // 使用修改后的URL（可能包含IP地址）
            var requestMessage = new HttpRequestMessage(HttpMethod.Put, requestUrl)
            {
                Content = content
            };

            return await Send(requestMessage, header);
        }

        /// <summary>
        /// 内部DELETE方法，使用HttpClient直接连接到指定IP
        /// </summary>
        private static async Task<JSONNode> DeleteInternal(JSONNode data, Dictionary<string, string> header, string requestUrl)
        {
            LogTools.Log($"Delete {requestUrl} {(data == null ? "empty" : data)}");
            var content = new StringContent((data == null ? "" : data.ToString()), Encoding.UTF8, "application/json");

            // 使用修改后的URL（可能包含IP地址）
            var requestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUrl)
            {
                Content = content
            };

            return await Send(requestMessage, header);
        }
        public static async Task<JSONNode> Send(HttpRequestMessage requestMessage, Dictionary<string, string> header = null)
        {
            LogTools.Log($"Send {requestMessage.RequestUri} ");
            // 设置自定义请求头（可以根据需要添加其他 header）
            // content.Headers.Add("Content-Type","application/json");
            var currentClient = client;
            if (header != null && header.Count > 0)
            {
                var e = header.GetEnumerator();
                var o = new JSONObject();
                while (e.MoveNext())
                {
                    var current = (KeyValuePair<string, string>)e.Current;
                    LogTools.Log($"Header {current.Key}: {current.Value}");
                    requestMessage.Headers.Add(current.Key, current.Value);
                    if (current.Key == "Cookie")
                    {
                        currentClient = cookieClient;
                    }
                }
            }
            
            var response = await currentClient.SendAsync(requestMessage);

            var responseContent = await response.Content.ReadAsStringAsync();
            // 从响应中获取 Cookie
            if (response.Headers.TryGetValues("Set-Cookie", out var cookieValues))
            {
                cookies = new List<string>(cookieValues.Select(r => r.Split(";")[0]));
                // Debug.LogError($"cookie: {string.Join("; ", cookies)}");
            }
            // LogTools.Log($"Result content: {responseContent}");
            var info = JSONNode.Parse(responseContent);
            info["response"] = response.StatusCode.ToString();
            LogTools.Log($"Result: {info}");
            return info;
        }
    }
}